<?php
/**
 * BugFree is free software under the terms of the FreeBSD License.
 *
 * BugFre api.
 *
 * @link        http://www.bugfree.org.cn
 * @package     BugFree
 */
/* Init BugFree system. */
require('Include/Init.inc.php');
require('Include/Api.inc.php');

define(SUCCESS, 'success');
define(FAILED, 'failed');

// init message info
$MessageInfo = array();

// validate input
if(!isset($_REQUEST['mode']))
{
    $MessageInfo['status'] = FAILED;
    $MessageInfo['code']   = $_CFG['API']['Error']['InputRequired']['Code'];
    $MessageInfo['info']   = '\'mode\' is required';
    echo createFailMsg($MessageInfo);
    exit;
}

// init the returned text's format
$Format = isset($_REQUEST['format']) && ($_REQUEST['format'] == 'json') ? 'json' : 'csv';
// init charset
$Charset = isset($_REQUEST['charset']) && (strtolower($_REQUEST['charset']) != 'utf8') ? 'utf8' : strtolower($_REQUEST['charset']);
if($Charset != 'utf8')
{
    $Format == 'csv';
}
// init mode
$Mode = $_REQUEST['mode'];

// init response header
@header("Content-Type: text/html; charset=$Charset");


switch($Mode)
{
    // get session
    case 'getsid':
    {
        $bfPage = new bfPage();
        $MessageInfo['sessionname'] = $bfPage->SessionName;
        $MessageInfo['sessionid'] = $bfPage->SessionID;
        $MessageInfo['rand'] = $bfPage->Rand;
        break;
    }

    // login
    case 'login':
    {   
        $bfUser = new bfUser($_REQUEST['username']);
        if(!$bfUser->login())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            $MessageInfo['timeout'] = $bfUser->ExpireTimestamp;
        }
        break;
    }

    // get bug, case, result info
    case 'getbug': case 'getcase': case 'getresult':
    {
        preg_match('/^get(bug|case|result)$/', $Mode, $regs);
        $lowerItem = $regs[1];
        $Item = ucfirst($lowerItem);
        $ID = $_REQUEST[$Item . 'ID'];

        $bfUser = new bfUser($_SESSION['TestUserName']);
        if(!$bfUser->isLogin())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            $MessageInfo = dbGetRow("{$Item}Info",$Coumns,"{$Item}ID = '{$ID}'  AND {$_SESSION[TestUserACLSQL]} AND IsDroped = '0'");

            if(empty($MessageInfo))
            {
                $MessageInfo['status'] = FAILED;
                $MessageInfo['code']   = 'API_ERROR_NOPERMISSION';
            }
            else
            {
                // add custom field info
                $tableName = testGetFieldTable($Item, $MessageInfo['ProjectID']);
                if(dbCheckTableExists($tableName))
                {
                    $TableName = testGetFieldTable($Item, $MessageInfo['ProjectID'], true);
                    $FieldInfo = dbGetRow($TableName, '', "FieldID = $ID");
                    if(is_array($FieldInfo))
                    {
                        foreach($FieldInfo as $key => $value)
                        {
                            if($key == 'FieldID')
                            {
                                continue;
                            }
                            $MessageInfo[$key] = $value;
                        }
                    }
                }
                // add action list
                $ActionList = testGetActionAndFileList($Item, $ID);
                $MessageInfo['ActionList'] = $ActionList['ActionList'];
            }
        }
        break;
    }

    // add bug, case, result
    case 'addbug': case 'addcase': case 'addresult':
    {
        preg_match('/^add(bug|case|result)$/', $Mode, $regs);
        $lowerItem = $regs[1];
        $Item = ucfirst($lowerItem);

        $bfUser = new bfUser($_SESSION['TestUserName']);
        if(!$bfUser->isLogin())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            $ProjectID = $bfUser->Param['ProjectID'];
            if($Mode == 'addresult')
            {
                $CaseInfo = dbGetRow('CaseInfo',$Coumns,"CaseID = '{$_REQUEST[CaseID]}'  AND {$_SESSION[TestUserACLSQL]} AND IsDroped = '0'");
                if(!empty($CaseInfo['ProjectID'])) $ProjectID = $CaseInfo['ProjectID'];
            }
            if($_SESSION['TestUserACL'][$ProjectID] != 'All')
            {
                $MessageInfo['status'] = FAILED;
                $MessageInfo['code']   = 'API_ERROR_NOPERMISSION';
            }
            else
            {
                // field's default value
                $FieldsValue = $_CFG['API']['FieldsDefauleValue'][$Item];
                $ID = apiAddItem($Item, $FieldsValue);
                if($ID > 0)
                {
                    $MessageInfo[$Item . 'ID'] = $ID;
                }
                else
                {
                    $MessageInfo['status'] = FAILED;
                    $MessageInfo['code']   = 'ADD_' . $Item . '_FAILED';
                }
            }
        }
        break;
    }

    // update bug, case, result
    case 'updatebug': case 'updatecase': case 'updateresult':
    {
        preg_match('/^update(bug|case|result)$/', $Mode, $regs);
        $lowerItem = $regs[1];
        $Item = ucfirst($lowerItem);
        $ID = $_REQUEST[$Item . 'ID'];

        $bfUser = new bfUser($_SESSION['TestUserName']);
        if(!$bfUser->isLogin())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            $ItemInfo = dbGetRow("{$Item}Info",$Coumns,"{$Item}ID = '{$ID}'  AND {$_SESSION[TestUserACLSQL]} AND IsDroped = '0'");
            if(empty($ItemInfo))
            {
                $MessageInfo['status'] = FAILED;
                $MessageInfo['code']   = 'API_ERROR_NOPERMISSION';
            }
            else
            {
                // field's default value
                $FieldsValue = $_CFG['API']['FieldsDefauleValue'][$Item];
                $Bingle = apiEditItem($Item, $FieldsValue, $ItemInfo);
                if($Bingle > 0)
                {
                    $MessageInfo['info']   = SUCCESS;
                }
                else
                {
                    $MessageInfo['status'] = FAILED;
                    $MessageInfo['code']   = 'UPDATE_' . $Item . '_FAILED';
                }
            }
        }
        break;
    }

    // get query
    case 'getquery':
    {
        set_time_limit(0);
        $QueryID = $_REQUEST['QueryID'];

        $bfUser = new bfUser($_SESSION['TestUserName']);

        if(!$bfUser->isLogin())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            $Page = isset($_REQUEST['page']) && $_REQUEST['page'] > 0 ? $_REQUEST['page'] : 1;
            $Size = isset($_REQUEST['size']) && $_REQUEST['size'] > 0  ? $_REQUEST['size'] : 500;
            $start = $Size * ($Page - 1);
            $end   =  $Size;
            $QueryInfo = dbGetRow('TestUserQuery', '', "QueryID='$QueryID'");
            if($QueryInfo['QueryType'])
            {
                $tableName = testGetFieldTable($QueryInfo['QueryType'], $QueryInfo['ProjectID']);
                $ItemList = null;
                if(dbCheckTableExists($tableName))
                {
                    $TableName = testGetFieldTable($QueryInfo['QueryType'], $QueryInfo['ProjectID'], true);
                    $ItemList = dbGetList($QueryInfo['QueryType'] . 'Info' . ", $TableName", '', "{$QueryInfo[QueryString]} AND {$_SESSION[TestUserACLSQL]} AND IsDroped = '0' AND $QueryInfo[QueryType]ID = FieldID",'','',"$start, $end",$QueryInfo['QueryType'] . 'ID');
                }
                else
                {
                    $ItemList = dbGetList($QueryInfo['QueryType'] . 'Info', '', "{$QueryInfo[QueryString]} AND {$_SESSION[TestUserACLSQL]} AND IsDroped = '0'",'','',"$start, $end",$QueryInfo['QueryType'] . 'ID');
                }
            }
            if($ItemList)
            {
                $Type = $QueryInfo['QueryType'];
                $TypeList = $ItemList;
                $ItemIds = '';
                if($Format == 'json')
                {
                    $MessageInfo[$Type . 'List'] = $TypeList;
                    foreach($TypeList as $Item)
                    {
                        $ItemIds .= $Item[$Type . 'ID'] . ',';
                    }
                }
                else
                {
                    $CVSList = "\n" . join(',', array_keys($_LANG[$Type . 'Fields'])) ."\n";
                    foreach($TypeList as $Item)
                    {
                        foreach($_LANG[$Type . 'Fields'] as $Key => $Value )
                        {
                            if($Key == 'FieldID')
                            {
                                continue;
                            }
                            $CVSList = $CVSList . '"' .iconv('utf-8', 'gbk', $Item[$Key]) . '"'. ',';
                        }
                        $ItemIds .= $Item[$Type . 'ID'] . ',';
                        $CVSList[strlen($CVSList)-1] = "\n";
                    }
                    $MessageInfo[$Type . 'CVSList'] = $CVSList;
                }
                $MessageInfo[$Type . "IDs"] = $ItemIds;
                $MessageInfo['size'] = $Size;
                $MessageInfo['page'] = $Page;
            }
            else
            {
                if($QueryInfo['QueryType'])
                {
                    $MessageInfo['status'] = FAILED;
                    $MessageInfo['code']   = 'NO_' . strtoupper($QueryInfo['QueryType']) . '_FOUND';
                }
                else
                {
                    $MessageInfo['status'] = FAILED;
                    $MessageInfo['code']   = 'NO_ITEM_FOUND';
                }
            }
        }
        break;
    }
    
    case 'query':
    {
        set_time_limit(0);
        $bfUser = new bfUser($_SESSION['TestUserName']);
        if(!$bfUser->isLogin())
        {
            $MessageInfo['status'] = FAILED;
            $MessageInfo['code']   = $bfUser->getErrorCode();
        }
        else
        {
            if(!isset($_REQUEST['query']))
            {
                $MessageInfo['status'] = FAILED;
                $MessageInfo['code']   = 'ARG_QUERY_REQUIRE';
            }
            else
            {
                $queryXml = sysStripSlash($_REQUEST['query']);
                $queryXml = preg_replace("/>\s+</","><",$queryXml);
                libxml_use_internal_errors(true);
                $xml = new DOMDocument();
                $xml->loadXML($queryXml);
                if($xml->schemaValidate('query.xsd'))
                {
                    $sql = '';
                    $query = $xml->getElementsByTagName('query');
                    $query = $query->item(0);
                    $table = dbGetPrefixTableNames($_CFG['Query']['Table'][$query->getAttribute('table')]);
                    $select =$query->getAttribute('select');
                    $wheresql = joinFields($query->firstChild, $where) . ' AND ' . $_SESSION[TestUserACLSQL] . ' AND IsDroped = "0"';
                    $page = null;
                    $size = null;
                    if($select == 'count(*)')
                    {
                        $sql = "SELECT count(*) FROM {$table} WHERE {$wheresql}";
                    }
                    else
                    {
                        $order = $query->getAttribute('order') ? $query->getAttribute('order') : '';
                        if($order)
                        {
                            $order =  'ORDER BY ' . $order;
                            $order .= $query->getAttribute('asc') ? ' ASC' : ' DESC';
                        }
                        $page = $query->getAttribute('page') ? $query->getAttribute('page') : 1;
                        $size = $query->getAttribute('size') ? $query->getAttribute('size') : 20;
                        $start = $size * ($page - 1);
                        $end   = $size;
                        $rawTable = $query->getAttribute('table');
                        $sql = "SELECT * FROM {$table} WHERE {$wheresql} {$order} LIMIT {$start}, {$end}";
                        if('Bug' == $rawTable || 'Case' == $rawTable)
                        {
                            $nodes = $query->getElementsByTagName('field');
                            for($i = 0; $i < $nodes->length; $i++)
                            {
                                $node = $nodes->item($i);
                                $field = $node->attributes->getNamedItem('name')->nodeValue;
                                $operator = $node->attributes->getNamedItem('operator')->nodeValue;
                                $value = $node->attributes->getNamedItem('value')->nodeValue;
                                $tableName = '';
                                if('EQ' == $operator)
                                {
                                    switch($field)
                                    {
                                        case 'ProjectID':
                                        {
                                            $tableName = testGetFieldTable($rawTable, $value);
                                            break;
                                        }
                                        case 'ProjectName':
                                        {
                                            $ProjectInfo = dbGetRow('TestProject', '', "ProjectName='{$value}'");
                                            $tableName = testGetFieldTable($rawTable, $ProjectInfo['ProjectID']);
                                            break;
                                        }
                                        case 'ModuleID':
                                        {
                                            $ModuleInfo = dbGetRow('TestModule', '', "ModuleID='{$value}'");
                                            $tableName = testGetFieldTable($rawTable, $ModuleInfo['ProjectID']);
                                            break;
                                        }
                                        default:
                                        {
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if(dbCheckTableExists($tableName))
                        {
                            $sql = str_replace($table, $table . ' LEFT JOIN ' . $tableName .' ON ' . $table . '.' . $rawTable .'ID = ' . $tableName . '.FieldID', $sql);
                        }
                    }
                    $ItemList = dbGetListBySql($sql);
                    if($ItemList)
                    {
                        $ItemIds = '';
                        if($Format == 'json')
                        {
                            $MessageInfo['QueryList'] = $ItemList;
                        }
                        else
                        {
                            $CVSList = "\n" . join(',', array_keys($ItemList[0])) ."\n";
                            foreach($ItemList as $Item)
                            {
                                foreach($Item as $Key => $Value )
                                {
                                    $CVSList = $CVSList . '"' . iconv('utf-8', 'gbk', $Item[$Key]) . '"'. ',';
                                }
                                $CVSList[strlen($CVSList)-1] = "\n";
                            }
                            $MessageInfo['CVSList'] = $CVSList;
                        }
                        if(isset($size))
                        {
                            $MessageInfo['size'] = $size;
                        }
                        if(isset($page))
                        {
                            $MessageInfo['page'] = $page;
                        }
                    }
                }
                else
                {
                    $MessageInfo['status'] = FAILED;
                    $errors = libxml_get_errors();
                    $error_count = count($errors);
                    for($i = 0; $i < $error_count; $i++)
                    {
                        $MessageInfo['code'] .=  "Error $num: ".trim($errors[$i+1]->message)." in file " . $errors[$i+1]->file . " on line " .$errors[$i+1]->line. "\n";
                    }
                    libxml_clear_errors();  
                }
            }
        }
        break;
    }
    
    default:
    {
        $MessageInfo['status'] = FAILED;
        $MessageInfo['code']   = 'UNKONW_FUNCTION';
    }
}

// output
if($Format == 'json')
{
    if(!isset($MessageInfo['status']))
    {
        $MessageInfo['status'] = SUCCESS;
    }
    echo json_encode($MessageInfo);
}
else
{
    if(isset($MessageInfo['status']))
    {
        echo createFailMsg($MessageInfo);
    }
    else
    {
        echo createSuccessMsg($MessageInfo);
    }
}

// join fields
function joinFields($node, $where)
{
    global $_CFG;
    for($i = 0; $i < $node->childNodes->length; $i++)
    {
        $cnode = $node->childNodes->item($i);
        if($cnode->nodeName == 'fields')
        {
            $where[] = joinFields($cnode, $where);
        }
        else
        {
            $field    = $cnode->attributes->getNamedItem('name')->nodeValue;
            $operator = $_CFG['Query']['Operator'][$cnode->attributes->getNamedItem('operator')->nodeValue];
            $value    = addslashes($cnode->attributes->getNamedItem('value')->nodeValue);
            $where[]  = "$field $operator '{$value}'";
        }
    }
    return '(' . join(' '. $node->getAttribute('logic'). ' ', $where) . ')';
}